home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Format CD 40
/
Amiga Format CD40 (1999-05-11)(Future Publishing)(GB)(Track 1 of 3)[!][issue 1999-06].iso
/
-seriously_amiga-
/
misc
/
pdflib
/
p_jpeg.c
< prev
next >
Wrap
C/C++ Source or Header
|
1999-03-24
|
10KB
|
379 lines
/* p_jpeg.c
* Copyright (C) 1997-98 Thomas Merz. All rights reserved.
*
* JPEG processing for PDFlib
*/
#include <stdio.h>
#include <string.h>
#ifdef POSIX
#include <unistd.h>
#endif
#include "p_intern.h"
/*
* The following enum is stolen from the IJG JPEG library
* Comments added by tm.
* This table contains far too many names since pdflib
* is rather simple-minded about markers.
*/
typedef enum { /* JPEG marker codes */
M_SOF0 = 0xc0, /* baseline DCT */
M_SOF1 = 0xc1, /* extended sequential DCT */
M_SOF2 = 0xc2, /* progressive DCT */
M_SOF3 = 0xc3, /* lossless (sequential) */
M_SOF5 = 0xc5, /* differential sequential DCT */
M_SOF6 = 0xc6, /* differential progressive DCT */
M_SOF7 = 0xc7, /* differential lossless */
M_JPG = 0xc8, /* JPEG extensions */
M_SOF9 = 0xc9, /* extended sequential DCT */
M_SOF10 = 0xca, /* progressive DCT */
M_SOF11 = 0xcb, /* lossless (sequential) */
M_SOF13 = 0xcd, /* differential sequential DCT */
M_SOF14 = 0xce, /* differential progressive DCT */
M_SOF15 = 0xcf, /* differential lossless */
M_DHT = 0xc4, /* define Huffman tables */
M_DAC = 0xcc, /* define arithmetic conditioning table */
M_RST0 = 0xd0, /* restart */
M_RST1 = 0xd1, /* restart */
M_RST2 = 0xd2, /* restart */
M_RST3 = 0xd3, /* restart */
M_RST4 = 0xd4, /* restart */
M_RST5 = 0xd5, /* restart */
M_RST6 = 0xd6, /* restart */
M_RST7 = 0xd7, /* restart */
M_SOI = 0xd8, /* start of image */
M_EOI = 0xd9, /* end of image */
M_SOS = 0xda, /* start of scan */
M_DQT = 0xdb, /* define quantization tables */
M_DNL = 0xdc, /* define number of lines */
M_DRI = 0xdd, /* define restart interval */
M_DHP = 0xde, /* define hierarchical progression */
M_EXP = 0xdf, /* expand reference image(s) */
M_APP0 = 0xe0, /* application marker, used for JFIF */
M_APP1 = 0xe1, /* application marker */
M_APP2 = 0xe2, /* application marker */
M_APP3 = 0xe3, /* application marker */
M_APP4 = 0xe4, /* application marker */
M_APP5 = 0xe5, /* application marker */
M_APP6 = 0xe6, /* application marker */
M_APP7 = 0xe7, /* application marker */
M_APP8 = 0xe8, /* application marker */
M_APP9 = 0xe9, /* application marker */
M_APP10 = 0xea, /* application marker */
M_APP11 = 0xeb, /* application marker */
M_APP12 = 0xec, /* application marker */
M_APP13 = 0xed, /* application marker */
M_APP14 = 0xee, /* application marker, used by Adobe */
M_APP15 = 0xef, /* application marker */
M_JPG0 = 0xf0, /* reserved for JPEG extensions */
M_JPG13 = 0xfd, /* reserved for JPEG extensions */
M_COM = 0xfe, /* comment */
M_TEM = 0x01, /* temporary use */
M_ERROR = 0x100 /* dummy marker, internal use only */
} JPEG_MARKER;
#define JPEG_BUFSIZE 512
static void
pdf_data_source_JPEG_init(PDF *p, PDF_data_source *src)
{
PDF_image *image;
image = (PDF_image *) src->private_data;
src->buffer_start = PDF_malloc(JPEG_BUFSIZE, "PDF_data_source_JPEG_init");
src->buffer_length = JPEG_BUFSIZE;
fseek(image->fp, image->startpos, SEEK_SET);
}
static bool
pdf_data_source_JPEG_fill(PDF *p, PDF_data_source *src)
{
PDF_image *image;
image = (PDF_image *) src->private_data;
src->next_byte = src->buffer_start;
src->bytes_available = fread(src->buffer_start, 1, JPEG_BUFSIZE, image->fp);
if (src->bytes_available == 0)
return false;
else
return true;
}
static void
pdf_data_source_JPEG_terminate(PDF *p, PDF_data_source *src)
{
PDF_image *image;
image = (PDF_image *) src->private_data;
PDF_free((void *) src->buffer_start);
}
/* read two byte parameter, MSB first */
#define get_2bytes(fp) ((unsigned int) (getc(fp) << 8) + getc(fp))
static int
pdf_next_jpeg_marker(FILE *fp)
{ /* look for next JPEG Marker */
int c, nbytes = 0;
if (feof(fp))
return M_ERROR; /* dummy marker */
do {
do { /* skip to FF */
nbytes++;
c = getc(fp);
} while (c != 0xFF);
do { /* skip repeated FFs */
c = getc(fp);
} while (c == 0xFF);
} while (c == 0); /* repeat if FF/00 */
return c;
}
/* open JPEG image and analyze marker */
PDF_image *
PDF_open_JPEG(PDF *p, char *filename)
{
int b, c, unit;
unsigned long i, length;
#define APP_MAX 255
unsigned char appstring[APP_MAX];
bool SOF_done = false;
PDF_image *image;
image = (PDF_image *) PDF_malloc(sizeof(PDF_image), "PDF_open_JPEG");
if (image == NULL)
return NULL;
if ((image->fp = fopen(filename, READMODE)) == NULL) {
pdf_error(p, PDF_WARN, "Couldn't open JPEG file %s\n", filename);
PDF_free(image);
return NULL;
}
image->filename = filename;
image->closefunc = PDF_close_JPEG;
image->compression = dct;
image->adobe = false;
image->dpi = 0.0;
image->indexed = false;
image->src.init = pdf_data_source_JPEG_init;
image->src.fill = pdf_data_source_JPEG_fill;
image->src.terminate = pdf_data_source_JPEG_terminate;
image->src.private_data = (void *) image;
/* Tommy's special trick for Macintosh JPEGs: simply skip some */
/* hundred bytes at the beginning of the file! */
do {
do { /* skip if not FF */
c = getc(image->fp);
} while (!feof(image->fp) && c != 0xFF);
do { /* skip repeated FFs */
c = getc(image->fp);
} while (c == 0xFF);
/* remember start position */
if ((image->startpos = ftell(image->fp)) < 0L) {
PDF_free(image);
return NULL;
}
image->startpos -= 2; /* subtract marker length */
if (c == M_SOI) {
fseek(image->fp, image->startpos, SEEK_SET);
break;
}
} while (!feof(image->fp));
#define BOGUS_LENGTH 768
/* Heuristics: if we are that far from the start chances are
* it is a TIFF file with embedded JPEG data which we cannot
* handle - regard as hopeless...
*/
if (feof(image->fp) || image->startpos > BOGUS_LENGTH) {
PDF_free(image);
return NULL;
}
/* process JPEG markers */
while (!SOF_done && (c = pdf_next_jpeg_marker(image->fp)) != M_EOI) {
switch (c) {
case M_ERROR:
PDF_free(image);
return NULL;
/* The following are not supported in PDF */
case M_SOF2:
case M_SOF3:
case M_SOF5:
case M_SOF6:
case M_SOF7:
case M_SOF9:
case M_SOF10:
case M_SOF11:
case M_SOF13:
case M_SOF14:
case M_SOF15:
PDF_free(image);
return NULL;
case M_SOF0:
case M_SOF1:
length = get_2bytes(image->fp); /* read segment length */
image->bpc = getc(image->fp);
image->height = get_2bytes(image->fp);
image->width = get_2bytes(image->fp);
image->components = getc(image->fp);
SOF_done = true;
break;
case M_APP0: /* check for JFIF marker with resolution */
length = get_2bytes(image->fp);
for (i = 0; i < length-2; i++) { /* get contents of marker */
b = getc(image->fp);
if (i < APP_MAX) /* store marker in appstring */
appstring[i] = b;
}
/* Check for JFIF application marker and read density values
* per JFIF spec version 1.02.
* We only check X resolution, assuming X and Y resolution are equal.
* Use values only if resolution not preset by user or to be ignored.
*/
#define ASPECT_RATIO 0 /* JFIF unit byte: aspect ratio only */
#define DOTS_PER_INCH 1 /* JFIF unit byte: dots per inch */
#define DOTS_PER_CM 2 /* JFIF unit byte: dots per cm */
if (length >= 14 && !strncmp("JFIF", (char *) appstring, 4)) {
unit = appstring[7]; /* resolution unit */
/* resolution value */
image->dpi = (appstring[8]<<8) + appstring[9];
if (image->dpi == 0.0)
break;
switch (unit) {
/* tell the caller we didn't find a resolution value */
case ASPECT_RATIO:
image->dpi = 0.0;
break;
case DOTS_PER_INCH:
break;
case DOTS_PER_CM:
image->dpi *= 2.54;
break;
default: /* unknown ==> ignore */
image->dpi = 0.0;
break;
}
}
break;
case M_APP14: /* check for Adobe marker */
length = get_2bytes(image->fp);
for (i = 0; i < length-2; i++) { /* get contents of marker */
b = getc(image->fp);
if (i < APP_MAX) /* store marker in appstring */
appstring[i] = b;
}
/* Check for Adobe application marker. It is known (per Adobe's TN5116)
* to contain the string "Adobe" at the start of the APP14 marker.
*/
if (length >= 12 && !strncmp("Adobe", (char *) appstring, 5))
image->adobe = true; /* set Adobe flag */
break;
case M_SOI: /* ignore markers without parameters */
case M_EOI:
case M_TEM:
case M_RST0:
case M_RST1:
case M_RST2:
case M_RST3:
case M_RST4:
case M_RST5:
case M_RST6:
case M_RST7:
break;
default: /* skip variable length markers */
length = get_2bytes(image->fp);
for (length -= 2; length > 0; length--)
(void) getc(image->fp);
break;
}
}
/* do some sanity checks with the parameters */
if (image->height <= 0 || image->width <= 0 || image->components <= 0) {
PDF_free(image);
return NULL;
}
if (image->bpc != 8) {
PDF_free(image);
return NULL;
}
switch(image->components) {
case 1:
image->colorspace = DeviceGray;
break;
case 3:
image->colorspace = DeviceRGB;
break;
case 4:
image->colorspace = DeviceCMYK;
break;
default:
PDF_free(image);
return NULL;
}
return image;
}
void
PDF_close_JPEG(PDF *p, PDF_image *image)
{
fclose(image->fp);
PDF_free(image);
}